//
//  UncaughtExceptionHandler.m
//  UncaughtExceptionHandler
//
//  Created by shaowei on 2/19/14.
//  Copyright (c) 2014 AISpeech. All rights reserved.
//

#import "UncaughtExceptionHandler.h"

static NSMutableArray *sMailReceivers;
static NSString *sMailTitlePrefix;
static NSString *sLogFilePath;

#define DefauleLogFileName @"Exception.txt"

@interface UncaughtExceptionHandler()

@property (nonatomic, strong) NSFileHandle *fileHandle;

@end

@implementation UncaughtExceptionHandler

+ (instancetype)sharedInstance{
    static UncaughtExceptionHandler *sInstance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sInstance = [[UncaughtExceptionHandler alloc] init];
    });
    
    return sInstance;
}

- (void)dealloc
{
    [_fileHandle synchronizeFile];
    [_fileHandle closeFile];
}

void MailUncaughtExceptionHandler(NSException * exception){

    NSString *nowDateStr = [UncaughtExceptionHandler getCurrentTime];
    
    NSString *mailReceivers = [sMailReceivers componentsJoinedByString:@","];
    NSString *mailTitle = [sMailTitlePrefix stringByAppendingFormat:@" - bug报告 %@",nowDateStr];
    NSString *exceptionName = [exception name];
    NSArray *exceptionContentArr = [exception callStackSymbols];
    NSString *exceptionReason = [exception reason];
    NSString *mailContent = [NSString stringWithFormat:@"%@<br>很抱歉应用出现故障,感谢您的配合!发送这封邮件可协助我们改善此应用<br>错误详情:<br>%@<br>--------------------<br>%@<br>------------------<br>%@",
                             nowDateStr,exceptionName,exceptionReason,[exceptionContentArr componentsJoinedByString:@"<br>"]];
    
    //写入本地
    NSString * exceptionLog = [UncaughtExceptionHandler getLogStringWithException:exception andTitle:@"crash"];
    [UncaughtExceptionHandler writeExceptionToLog:exceptionLog];
    NSFileHandle *fileHandle = [[UncaughtExceptionHandler sharedInstance] fileHandle];
    [fileHandle synchronizeFile];
    [fileHandle closeFile];
    
    
    //发邮件
	NSString *mailURLStr = [NSString stringWithFormat:@"mailto:%@?subject=%@&body=%@",
                            mailReceivers,mailTitle,mailContent];
	
	NSURL *mailURL = [NSURL URLWithString:[mailURLStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
	[[UIApplication sharedApplication] openURL:mailURL];
}

#pragma mark - Function - Public

+ (void)addMailReceiver:(NSString *)mailReceiver{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sMailReceivers = [NSMutableArray arrayWithCapacity:0];
    });
    if (![sMailReceivers containsObject:mailReceiver]) {
        [sMailReceivers addObject:mailReceiver];
    }
}


+ (void)setMailTitlePrefix:(NSString *)mailPrefix{
    sMailTitlePrefix = mailPrefix;
}

+ (void)setDefaultHandler
{
    NSSetUncaughtExceptionHandler(&MailUncaughtExceptionHandler);
    
    //初始化
    NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"];
    NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
    sMailTitlePrefix = [NSString stringWithFormat:@"%@ %@",appName,appVersion];
    [self setLogFileName:DefauleLogFileName];
}

+ (NSUncaughtExceptionHandler *)getHandler
{
    return NSGetUncaughtExceptionHandler();
}

+ (void)TakeException:(NSException *)exception{
    NSString * exceptionLog = [self getLogStringWithException:exception andTitle:@"try"];
    [UncaughtExceptionHandler writeExceptionToLog:exceptionLog];
}

#pragma mark private

+ (NSString *)getLogStringWithException:(NSException *)exception andTitle:(NSString *)title{
    NSArray *arr = [exception callStackSymbols];
    NSString *reason = [exception reason];
    NSString *name = [exception name];
    NSString *time = [self getCurrentTime];
    
    NSString * exceptionLog = [NSString stringWithFormat:@"\n\n\n========%@ Exception错误报告========\nhappen time:%@\nname:%@\nreason:\n%@\ncallStackSymbols:\n%@",title,time,name,reason,[arr componentsJoinedByString:@"\n"]];
    return exceptionLog;
}

+ (NSString *)getCurrentTime{
    NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
    [dateFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSString *nowDateStr = [dateFormat stringFromDate:[NSDate date]];
    return nowDateStr;
}

#pragma mark - file-log

+ (BOOL)setLogFileName:(NSString *)logFileName{
    if (logFileName.length) {
        sLogFilePath = [self getAppDocumentPath:logFileName];
        if (![[NSFileManager defaultManager] fileExistsAtPath:sLogFilePath]) {
            //文件不存在 --- 创建文件
            [[NSFileManager defaultManager] createFileAtPath:sLogFilePath
                                                    contents:nil
                                                  attributes:nil];
        }
        
        [self resetFileHandlerWithPath:sLogFilePath];
        return YES;
    }
    
    return NO;
}

#pragma mark private

/**
 返回App文件夹下的Document目录路径，加上参数的子路径 (Document).
 @param Document目录下的子路径
 @returns 完整路径
 */
+ (NSString *)getAppDocumentPath:(NSString *)extraPath{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentPath = [paths objectAtIndex:0];
    if (extraPath) {
        documentPath = [documentPath stringByAppendingPathComponent:extraPath];
    }
    
    return documentPath;
}

+ (NSString *)logFileDefaultPath{
    return [self getAppDocumentPath:DefauleLogFileName];
}

+ (void)resetFileHandlerWithPath:(NSString *)path{
    NSFileHandle *fileHandle = [[self sharedInstance] fileHandle];
    if (fileHandle) {
        [fileHandle synchronizeFile];
        [fileHandle closeFile];
    }
    
    fileHandle = [NSFileHandle fileHandleForWritingAtPath:path];
    [fileHandle seekToEndOfFile];
    [[self sharedInstance] setFileHandle:fileHandle];
}

+ (void)writeExceptionToLog:(NSString *)exceptionStr{
    NSFileHandle *fileHandle = [[self sharedInstance] fileHandle];
    NSData *data = [exceptionStr dataUsingEncoding:NSUTF8StringEncoding];
    [fileHandle writeData:data];
}





@end
